using UnityEngine;

public class PlayerMove : MonoBehaviour
{
    [Header("Move")]
    //�ƶ�����
    public float _speed = 8.0f;

    [SerializeField] private float _runSpeed = 16f;
    public float crouchSpeedDivisor = 3f;

    //��Ծ����
    public float jumpForce = 6.3f;
    public float jumpHoldForce = 1.9f;
    public float jumpHoldDuration = 0.1f;
    public float crouchjumpBoost = 2.5f;
    public float handingJumpForce = 15f;

    [Header("Status")]
    //״̬
    public bool isCrouch;

    public bool isOnGround;
    public bool isJump;
    public bool isHeadBlock;
    public bool isHanding;

    [Header("PhysicsCheck")]
    //�������
    public LayerMask groundLayer;

    //���߼����ײ
    public float footOffset = 0.3f;
    public float groundDistance = 0.2f;
    public float headDistance = 0.2f;
    public float eyeHeight = 1.5f;
    public float grabDistance = 0.4f;
    public float reachOffset = 0.7f;

    //overLapBox���
    [SerializeField] private Vector2 _boxSize;

    public float xVelocity;
    private bool _isLeftShiftPressed;
    private BoxCollider2D boxColl;
    private Vector2 colliderCrouchOffset;
    private Vector2 colliderCrouchSize;
    private Vector2 colliderStandOffset;

    //����ԭ�е���ײ��ĳߴ�
    private Vector2 colliderStandSize;
    private bool crouchHold;
    private bool crouchPressed;
    private bool jumpHold;

    //��λ�ж�
    private bool jumpPressed;

    //��Ծʱ���ڲ�
    private float jumpTime;
    private float playerHeight;
    private Rigidbody2D rb;

    //����ԭ����Ҫ������ײ���ԭʼ����
    private Vector3 ScaleSize;


    // Start is called before the first frame update
    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        boxColl = GetComponent<BoxCollider2D>();
        playerHeight = boxColl.size.y;

        colliderStandSize = boxColl.size;
        colliderStandOffset = boxColl.offset;
        colliderCrouchSize = new Vector2(boxColl.size.x, boxColl.size.y / 2f);
        colliderCrouchOffset = new Vector2(boxColl.offset.x, boxColl.offset.y / 2f);

        footOffset = boxColl.size.x * transform.localScale.x / 2;

        ScaleSize = transform.localScale;
    }


    // Update is called once per frame
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.LeftShift)) _isLeftShiftPressed = true;
        if (Input.GetButtonDown("Jump")) jumpPressed = true;
        jumpHold = Input.GetButton("Jump");
        crouchHold = Input.GetButton("Crouch");
        if (Input.GetButton("Crouch")) crouchPressed = true;
        else crouchPressed = false;
    }

    private void FixedUpdate()
    {
        PyhsicsCheck();
        GroundMoved();
        MidAirMovement();
    }

    private void OnDrawGizmos()
    {
        Gizmos.DrawWireCube(transform.position, _boxSize);
        Gizmos.color = Color.red;
    }

    //�жϽ�ɫ�Ƿ���ĳ���㼶��
    private void PyhsicsCheck()
    {
        //���ҽ��ŵ��ж�
        var OnGroundCheck = Physics2D.OverlapBox(transform.position, _boxSize, 0, groundLayer);

        if (OnGroundCheck != null) isOnGround = true;
        else isOnGround = false;

        //ͷ���赲�ж�
        var headCheck = Raycast(new Vector2(0f, boxColl.size.y), Vector2.up, headDistance, groundLayer);
        if (headCheck) isHeadBlock = true;
        else isHeadBlock = false;

        //����״̬�ж�
        var direction = transform.localScale.x;
        var grabDir = new Vector2(direction, 0f);

        var blockCheck = Raycast(new Vector2(footOffset * direction, playerHeight), grabDir, grabDistance, groundLayer);
        var wallCheck = Raycast(new Vector2(footOffset * direction, eyeHeight), grabDir, grabDistance, groundLayer);
        var ledgeCheck = Raycast(new Vector2(reachOffset * direction, playerHeight), Vector2.down, grabDistance,
            groundLayer);

        if (!isOnGround && rb.velocity.y < 0f && ledgeCheck && wallCheck && !blockCheck)
        {
            var pos = transform.position;
            pos.x += (wallCheck.distance - 0.5f) * direction;
            pos.y -= ledgeCheck.distance;
            transform.position = pos;

            rb.bodyType = RigidbodyType2D.Static;
            isHanding = true;
        }
    }

    private void GroundMoved()
    {
        if (isHanding)
        {
            if (crouchPressed)
            {
                rb.bodyType = RigidbodyType2D.Dynamic;
                isHanding = false;
            }

            if (jumpPressed)
            {
                rb.bodyType = RigidbodyType2D.Dynamic;
                rb.velocity = new Vector2(0f, handingJumpForce);
                isHanding = false;
            }

            return;
        }

        if (crouchHold)
            Crouch();
        else if (!crouchHold && isCrouch && !isHeadBlock)
            StandUp();

        xVelocity = Input.GetAxis("Horizontal");

        //����leftshift���ɫ��ֹ��
        var speed = _speed;
        if (_isLeftShiftPressed) speed = _runSpeed;
        rb.velocity = new Vector2(xVelocity * speed, rb.velocity.y);
        FilpDirrction();
    }

    private void FilpDirrction()
    {
        var v3 = new Vector3(0 - ScaleSize.x, ScaleSize.y, ScaleSize.z);
        if (xVelocity < 0)
            transform.localScale = v3;
        if (xVelocity > 0)
            transform.localScale = ScaleSize;
    }

    private void Crouch()
    {
        isCrouch = true;
        boxColl.size = colliderCrouchSize;
        boxColl.offset = colliderCrouchOffset;
    }

    private void StandUp()
    {
        isCrouch = false;
        boxColl.size = colliderStandSize;
        boxColl.offset = colliderStandOffset;
    }

    private void MidAirMovement()
    {
        if (jumpPressed && isOnGround && !isJump)
        {
            if (isCrouch & isOnGround)
            {
                StandUp();
                rb.AddForce(new Vector2(0f, crouchjumpBoost), ForceMode2D.Impulse);
            }

            isOnGround = false;
            isJump = true;

            jumpTime = Time.time + jumpHoldDuration;

            //addforce�����У�forcemode2d�������������˼��ͻȻ����һ����
            rb.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
            jumpPressed = false;
            //AudioManager.PlayJumpAudio();
        }
        else if (isJump)
        {
            if (jumpHold)
                rb.AddForce(new Vector2(0f, jumpHoldForce), ForceMode2D.Impulse);
            if (jumpTime < Time.time)
                isJump = false;
        }
    }

    private RaycastHit2D Raycast(Vector2 offset, Vector2 rayDiration, float length, LayerMask layer)
    {
        Vector2 pos = transform.position;

        var hit = Physics2D.Raycast(pos + offset, rayDiration, length, layer);

        var color = hit ? Color.red : Color.green;

        Debug.DrawRay(pos + offset, rayDiration * length, color);

        return hit;
    }
}